import { AFFIX_TEMPLATE, AFFIX_REGEXP } from "../../A-FRAME/frame.config";
import { http_send } from "../../A-FRAME/network/HttpService";
import { HSAPIURI, HSAPIStructMap, HSReq, HSRes, HSBody, DEFAULT_BODY } from "./api.config.service";

const ServerURL = "http://am.33t8y678tyy6rt.top/";

export default class ServiceAPI {
	private static used_token: string[] = [];
	private static async send<uri extends HSAPIURI>(api: uri, data?: HSAPIStructMap[uri]['request']['data']) {

		let url = ServerURL + api;

		let request: HSReq<uri> = {} as any;
		request.ccToken = mtec.string.randomToken(5, 36, t => !ServiceAPI.used_token.includes(t));
		request.data = data;
		Object.assign(request, DEFAULT_BODY);
		ServiceAPI.used_token.push(request.ccToken);

		formatRequest(request);
		let response: Awaited<HSRes<uri>> = await http_send(url, request, 'POST');
		parseResponse(response);

		if (!(response?.success)) {
			let np = new mtec.NudityPromise<any>();
			this.exception_list.unshift({ url, request, np, count: 0 });
			this.retryException();
			response = await np.promise;
		}

		return response;
	}

	private static exception_list: Array<{ url: string, request: any, np: mtec.NudityPromise<any>, count: number }> = [];
	private static exception_call: () => Promise<[boolean, number]>;

	public static onException(call: () => Promise<[boolean, number]>) {
		this.exception_call = call;
	}

	private static retry_exception_lock = false;
	private static retry_limit = Infinity;
	private static retry_count = 0;
	private static async retryException() {
		if (ServiceAPI.retry_count >= ServiceAPI.retry_limit) {
			ServiceAPI.exception_list.splice(0, ServiceAPI.exception_list.length).forEach(e => e.np.resolve(undefined));
			ServiceAPI.retry_count = 0;
			ServiceAPI.retry_limit = Infinity;
			return void 0;
		}
		ServiceAPI.retry_count++;
		if (ServiceAPI.retry_exception_lock) {
			return void 0;
		}
		ServiceAPI.retry_exception_lock = true;

		let network: boolean;
		if (ServiceAPI.exception_call) {
			[network, ServiceAPI.retry_limit] = await ServiceAPI.exception_call();
		}

		let item: typeof ServiceAPI.exception_list[number];
		let response: Awaited<HSRes<HSAPIURI>>
		while (ServiceAPI.exception_list.length > 0) {
			item = ServiceAPI.exception_list.pop();
			if (item.count == 0) {
				item.count++;
				response = await http_send(item.url, item.request, 'POST');
				parseResponse(response);
				if (!response?.success) {
					ServiceAPI.exception_list.unshift(item);
				} else {
					item.np.resolve(response);
				}
			} else {
				ServiceAPI.exception_list.unshift(item);
				break;
			}
		}

		ServiceAPI.retry_exception_lock = false;
		if (ServiceAPI.exception_list.length > 0) {
			ServiceAPI.exception_list.forEach(_ => _.count = 0);
			ServiceAPI.retryException();
		} else {
			ServiceAPI.retry_count = 0;
			ServiceAPI.retry_limit = Infinity;
		}
	}

	public static INIT_DEFAULT_BODY(call: (body: typeof DEFAULT_BODY) => void) {
		call(DEFAULT_BODY);
	}

	/**
	 * 初始化用户
	 * @param deviceId
	 * @param country
	 * @returns
	 */
	public static async initUser(
		deviceId: HSBody<HSAPIURI.UserInit>['deviceId'],
		country: HSBody<HSAPIURI.UserInit>['country']
	) {
		let response: Awaited<HSRes<HSAPIURI.UserInit>>;
		let count = 0;
		while (!response?.success && (count < 3)) {
			count++;
			response = await ServiceAPI.send(HSAPIURI.UserInit, { deviceId, country });
		}
		// let response = await ServiceAPI.send(HSAPIURI.UserInit, { deviceId, country });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 获取用户信息
	 * @param userId
	 * @returns
	 */
	public static async userInfo(
		userId: HSBody<HSAPIURI.UserInfo>['userId']
	) {
		let response: Awaited<HSRes<HSAPIURI.UserInfo>>;
		let count = 0;
		while (!response?.success && (count < 3)) {
			count++;
			response = await ServiceAPI.send(HSAPIURI.UserInfo, { userId });
		}
		// let response = await ServiceAPI.send(HSAPIURI.UserInfo, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 地域配置数据
	 * @param country
	 * @returns
	 */
	public static async ConfCountry(
		country: HSBody<HSAPIURI.ConfCountry>['country']
	) {
		let response: Awaited<HSRes<HSAPIURI.ConfCountry>>;
		let count = 0;
		while (!response?.success && (count < 3)) {
			count++;
			response = await ServiceAPI.send(HSAPIURI.ConfCountry, { country });
		}

		// let response = await ServiceAPI.send(HSAPIURI.ConfCountry, { country });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 项目其他配置
	 * @param userId
	 * @returns
	 */
	public static async ConfCommon(
		userId: HSBody<HSAPIURI.ConfCommon>['userId']
	) {
		let response: Awaited<HSRes<HSAPIURI.ConfCommon>>;
		let count = 0;
		while (!(response?.success) && (count < 3)) {
			count++;
			response = await ServiceAPI.send(HSAPIURI.ConfCommon, { userId });
		}
		// let response = await ServiceAPI.send(HSAPIURI.ConfCommon, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 提现配置数据
	 * @param userId
	 * @returns
	 */
	public static async WithdrawConfig(
		userId: HSBody<HSAPIURI.WithdrawConfig>['userId']
	) {
		let response = await ServiceAPI.send(HSAPIURI.WithdrawConfig, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 新人现金奖励数值获取
	 * @param userId
	 * @param getCashType
	 * @returns
	 */
	public static async GetNewComerReward(
		userId: HSBody<HSAPIURI.GetNewComerReward>['userId']
	) {
		let response: Awaited<HSRes<HSAPIURI.GetNewComerReward>>;
		let count = 0;
		while (!response?.success && (count < 3)) {
			count++;
			response = await ServiceAPI.send(HSAPIURI.GetNewComerReward, { userId });
		}
		// let response = await ServiceAPI.send(HSAPIURI.GetNewComerReward, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 抽奖结果获取
	 * @param userId
	 * @returns
	 */
	public static async LotteryConfig(
		userId: HSBody<HSAPIURI.LotteryConfig>['userId']
	) {
		let response = await ServiceAPI.send(HSAPIURI.LotteryConfig, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 过关面板现金数值获取
	 * @param userId
	 * @returns
	 */
	public static async PassLevelConfig(
		userId: HSBody<HSAPIURI.PassLevelConfig>['userId']
	) {
		let response = await ServiceAPI.send(HSAPIURI.PassLevelConfig, { userId });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 过关面板现金领取上报
	 * @param userId
	 * @param packCash
	 * @param packGetType
	 * @returns
	 */
	public static async PassLevelReport(
		userId: HSBody<HSAPIURI.PassLevelReport>['userId'],
		cashAmount: HSBody<HSAPIURI.PassLevelReport>['cashAmount'],
		getType: HSBody<HSAPIURI.PassLevelReport>['getType']
	) {
		let response = await ServiceAPI.send(HSAPIURI.PassLevelReport, { userId, cashAmount, getType });
		return response?.success ? response.result : void 0;
	}
	/**
	 * 消除成功上报
	 * @param userId 
	 * @returns 
	 */
	public static async EliminateReport(
		userId: HSBody<HSAPIURI.EliminateReport>['userId'],
	) {
		let response = await ServiceAPI.send(HSAPIURI.EliminateReport, { userId });
		return response?.success ? response.result : void 0;
	}

}

function formatRequest(request: any) {
	let list = [];

	if (typeof request == 'object' && !Array.isArray(request)) {
		list.unshift(request);
	}

	while (list.length > 0) {
		let item = list.pop();
		if (Array.isArray(item)) {
			item.forEach(el => {
				if (typeof el == 'object') {
					list.unshift(el);
				}
			});
		} else {
			for (let [key, value] of Object.entries(item)) {
				if (typeof value == 'object' && value !== null) {
					list.unshift(value);
				}

				Reflect.deleteProperty(item, key);
				Reflect.set(item, AFFIX_TEMPLATE.replace('key', key), value);
			}
		}
	}

	return request;
}

function parseResponse(response: any) {
	let list = [];

	if (typeof response == 'object' && !Array.isArray(response)) {
		list.unshift(response);
	}

	while (list.length > 0) {
		let item = list.pop();
		if (Array.isArray(item)) {
			item.forEach(el => {
				if (typeof el == 'object' && el !== null) {
					list.unshift(el);
				}
			});
		} else if (item) {
			for (let [key, value] of Object.entries(item)) {
				if (typeof value == 'object' && value !== null) {
					list.unshift(value);
				}

				Reflect.deleteProperty(item, key);
				Reflect.set(item, key.replace(AFFIX_REGEXP, '$1'), value);
			}
		}
	}

	return response;
}